<?php

namespace ticky;

use ticky\lang;

class app {

    public static $namespace = 'application';
    public static $config = [];
    private $initated = false; //是否初始化过
    private static $superglobal = array(
        'GLOBALS' => 1,
        '_GET' => 1,
        '_POST' => 1,
        '_REQUEST' => 1,
        '_COOKIE' => 1,
        '_SERVER' => 1,
        '_ENV' => 1,
        '_FILES' => 1,
    );

    public static function &instance() {
        static $object;
        if (empty($object)) {
            $object = new self();
        }
        return $object;
    }

    public function __construct() {
        $this->_init_env();
        $this->_init_config();
        $this->_init_input();
        $this->_init_output();
    }

    // 运行应用
    public function run(request $req = null) {
        if (!$this->initated) {
            $this->_init_lang();
        }
        $this->initated = true;
        // 路由分发
        route::dispatch();
    }

    private function _init_env() {
        @set_time_limit(0);
        define('ICONV_ENABLE', function_exists('iconv'));
        define('MB_ENABLE', function_exists('mb_convert_encoding'));
        define('EXT_OBGZIP', function_exists('ob_gzhandler'));
        if (version_compare(PHP_VERSION, '5.4.0', '<')) {
            ini_set('magic_quotes_runtime', 0);
            define('MAGIC_QUOTES_GPC', get_magic_quotes_gpc() ? true : false);
        } else {
            define('MAGIC_QUOTES_GPC', false);
        }

        if (function_exists('ini_get')) {
            $memorylimit = @ini_get('memory_limit');
            if ($memorylimit && return_bytes($memorylimit) < 33554432 && function_exists('ini_set')) {
                ini_set('memory_limit', '128m');
            }
        }
        foreach ($GLOBALS as $key => $value) {
            if (!isset(self::$superglobal[$key])) {
                $GLOBALS[$key] = null;
                unset($GLOBALS[$key]);
            }
        }
        define('FORMHASH', formhash());
        global $_G;
        $_G = array(
            'uid' => session('uid'),
            'username' => session('username'),
            'adminid' => session('adminid'),
            'groupid' => session('groupid'),
            'formhash' => FORMHASH,
            'timestamp' => TIMESTAMP,
            'config' => array(),
            'setting' => cache('setting'),
            'cookie' => $_COOKIE,
            'cache' => array(),
            'session' => $_SESSION,
            'md5data' => array(),
            'define' => array(
                'TICKY_VERSION' => TICKY_VERSION,
                'ROOT_PATH' => dirname(TICKY_PATH) . DS,
                'TICKY_PATH' => dirname(dirname(__FILE__)) . DS,
                'TICKY_LIB' => TICKY_PATH . 'library' . DS,
                'TICKY_CONFIG' => TICKY_PATH . 'config' . DS,
                'APP_PATH' => ROOT_PATH . 'application' . DS,
                'PATH' => APP_PATH . DS . 'common',
                'APP_ENV' => ini_get('app_env') ? ini_get('app_env') : 'develop',
                'HTTP_HOST' => $_SERVER['HTTP_HOST'],
                'SERVER_PORT' => isset($_SERVER['SERVER_PORT']) && $_SERVER['SERVER_PORT'] == '443' ? 'https://' : 'http://',
                'SITE_PATH' => str_replace('index.php', '', PHP_FILE),
                'SITE_URL' => SERVER_PORT . HTTP_HOST . SITE_PATH,
                'IS_CGI' => (0 === strpos(PHP_SAPI, 'cgi') || false !== strpos(PHP_SAPI, 'fcgi')) ? 1 : 0,
                'PHP_FILE' => PHP_FILE
            ),
            'lang' => lang::get(),
        );
    }

    private function _init_config() {
        self::$config = config::get('app');
        // 获取APP命名空间
        self::$namespace = '\\' . self::$config['app_namespace'];
        loader::addNamespace(self::$namespace, APP_PATH);
        if (!empty(self::$config['root_namespace'])) {
            loader::addNamespace(self::$config['root_namespace']);
        }
    }

    private function _init_input() {
        if (isset($_GET['GLOBALS']) || isset($_POST['GLOBALS']) || isset($_COOKIE['GLOBALS']) || isset($_FILES['GLOBALS'])) {
            self::halt('request_tainting');
        }
        if (MAGIC_QUOTES_GPC) {
            $_GET = dstripslashes($_GET);
            $_POST = dstripslashes($_POST);
            $_COOKIE = dstripslashes($_COOKIE);
        }
        if ($_SERVER['REQUEST_METHOD'] == 'POST' && !empty($_POST)) {
            $_GET = array_merge($_GET, $_POST);
        }
        if (!(!empty($_GET['handlekey']) && preg_match('/^\w+$/', $_GET['handlekey']))) {
            unset($_GET['handlekey']);
        }
    }

    private function _init_output() {
        // 设置页面编码
        date_default_timezone_set(self::$config['default_timezone']);
        // 设置页面编码，这里需要优化下，cli模式下无需设置
        header("Content-type: text/html; charset=" . self::$config['default_charset']);
        // 设置X-Powered-By X-CSRF-Token
        header('X-Powered-By:TickyPHP V' . TICKY_VERSION);
        header('X-CSRF-Token:' . FORMHASH);
        defined('CHARSET') or define('CHARSET', self::$config['default_charset']);
    }

    private function _init_lang() {
        $langset = strtolower(config::get('lang', 'default_lang'));
        $lang_switch_on = strtolower(config::get('lang', 'lang_switch_on'));
        // 默认语言
        lang::range($langset);
        // 设置允许的语言
        lang::setAllowLangList(['zh-cn', 'en-us']);
        // 开启多语言机制 检测当前语言
        $lang_switch_on && lang::detect();

        // 加载系统语言包
        //框架语言包: tickyphp\lang\当前语言.php
        //应用语言包: application\lang\当前语言.php
        //模块语言包: application\模块\lang\当前语言.php
        lang::load([
            TICKY_PATH . DS . 'lang' . DS . lang::range() . ".php",
            APP_PATH . DS . 'lang' . DS . lang::range() . ".php",
            APP_PATH . DS . 'common' . DS . 'lang' . DS . lang::range() . ".php",
        ]);
        setglobal('lang', lang::range());
    }

    /**
     *  提示信息页面跳转
     *
     * @param     string  $msg      消息提示信息
     * @param     string  $gourl    跳转地址
     * @param     int     $limittime  限制时间
     * @return    void
     */
    public static function showmsg($msg, $gourl, $limittime) {
        $gourl = empty($gourl) ? HTTP_REFERER : $gourl;
        $stop = $gourl != 'stop' ? false : true;
        include(TICKY_PATH . DS . 'tpl' . DS . 'message.tpl');
    }

    /**
     * 打开调式模式情况下, 输出致命错误
     *
     * @param     string  $msg      提示信息
     * @param     string  $detailed	详细信息
     * @param     string  $type     错误类型 1:php 2:mysql
     * @return    void
     */
    public static function fatalerror($msg, $detailed = '', $type = 1) {
        if (ob_get_length() !== false)
            @ob_end_clean();
        include(TICKY_PATH . DS . 'tpl' . DS . 'error.tpl');
        exit();
    }

    /**
     *  输出错误提示
     *
     * @param     string  $msg      提示信息
     * @return    void
     */
    public static function halt($msg) {
        if (ob_get_length() !== false)
            @ob_end_clean();
        header('HTTP/1.1 404 Not Found');
        header('Status:404 Not Found');
        include(TICKY_PATH . DS . 'tpl' . DS . 'halt.tpl');
        exit();
    }

}
